所謂最小化存取權限,其實就是隱藏不必要給其他使用者知道資訊,這麼做的好處有:
public
,把欄位設為public
,不只不好維護,還讓mutable的物件變得不thread-safe。Java共有規範三種存取權限的modifier,分別是private
、protected
和public
,另外,如果類別、欄位或方法沒有modifier,則被視為package-private
,這四種存取權限的定義如下:
private
:只能被同一類別的其他成員存取。package-private
:只能被同一個package的類別存取,如果類別、欄位或方法沒有加modifier,預設會是package-private
。如果該類別只有被一個類別使用,建議把該類別轉為nested class。protected
:只能被同一類別和子類別存取。public
:可以被所有類別存取。一般來說,如果被設為private
或package-private
,應該不會出現在exported API,但如果類別有實作Serializable
,被設為private
或package-private
的欄位,有可能被洩漏出來。
子類別繼承父類別之後,子類別覆寫方法後的存取權限,不可低於父類別,舉例來說,父類別的方法如果是protected
,子類別繼承後覆寫該方法,只能是protected
或public
,不能是private
和package-private
,不然會出現compile error。而interface的方法預設皆為public
,實作的時候也不能改變。
而在測試時,常常會有"我想測這個方法,但是它是private
,無法存取!!!"的問題,這時候可以將測試程式跟要測試的類別放在同一個package,並把方法的modifier,變成package-private
,就可以在最小存取權限下進行測試。
以Java的設計,有static final
屬性的欄位,在類別實體化之後,應該不能被修改,但卻有一個例外,如果這個欄位存的型別是array,由於array是mutable的,即使是static final
,一旦被設為public
,還是可以被其它使用者修改。下面Draw
這個範例,Draw
被實體化了,但還是可以修改COLORS
裡面的內容。
import java.util.Arrays;
public class Draw {
// 設定一個 public static final 數組
public static final String[] COLORS = {"Red", "Green", "Blue"};
public static void main(String[] args) {
Draw draw = new Draw();
// 嘗試修改數組的內容
draw.COLORS[0] = "Yellow";
System.out.println(Arrays.toString(draw.COLORS));
}
}
要避免這個情況,可以選擇改用list,並使用Collections.unmodifiableList
產生immutable的list。
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Draw {
// 設定一個 public static final 數組
public static final List<String> COLORS = Collections.unmodifiableList(Arrays.asList("Red", "Green", "Blue"));
public static void main(String[] args) {
Draw draw = new Draw();
// 嘗試修改數組的內容
draw.COLORS.set(0, "Yellow");
System.out.println(draw.COLORS);
}
}
當嘗試要修改list內容的時候,runtime會丟出exception警告。
如果真的想要把欄位設為public
,那麼該欄位最好是immutable,並把欄位設為final
,會讓改動之後的損害變得比較小。當然,如果是private
或package-private
的類別,把欄位設為public
的影響比較沒那麼大,也是可被接受的。
除了把欄位設為final
之外,也可以使用getter和setter,這樣調整欄位的時候只要確保getter和setter結果如預期即可,但如果是直接存取欄位,測試的範圍會變大。
Reference:
Controlling Access to Members of a Class